package com.yfs.cloud.aop;

import java.util.List;
import java.util.Objects;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.yfs.cloud.annotation.DataAuthChecker;
import com.yfs.cloud.authority.AuthChecker;
import com.yfs.cloud.authority.UserAuthority;
import com.yfs.cloud.authority.UserAuthorityContextHolder;
import com.yfs.cloud.commons.BusinessException;
import com.yfs.cloud.commons.ResultCode;

/**
* @Company: 影法師工作室
* @Description: 数据接口鉴权切面
* @author 影法師  
* @date 2020年8月28日 上午11:04:14 
* @version V1.0
 */
@Aspect
@Component
public class DataAuthCheckerAspect {

	// service.impl 包下面的任何类的任何方法
	@Pointcut("execution(public * com.yfs.cloud.service.impl.*.*(..))")
	public void doNothing() {
	}

	@Before("doNothing()")
	public void doBefore(JoinPoint joinPoint) throws Exception {
		// 获取当前用户角色、模块权限等信息
		UserAuthority userAuthority = UserAuthorityContextHolder.getUserInfo();
		// 如果不需要进行 jwt 鉴权, 则 userAuthority 是空的. 则直接放心
		if (Objects.isNull(userAuthority)) {
			return;
		}
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
		// 尝试获取service方法上的 DataAuthChecker 注解
		DataAuthChecker dataAuthChecker = methodSignature.getMethod().getDeclaredAnnotation(DataAuthChecker.class);
		// 如果没有 DataAuthChecker 注解的话, 直接返回 true, 表示不需要数据接口鉴权
		if (Objects.isNull(dataAuthChecker)) {
			return;
		}
		// 获取需要什么权限才能访问此数据接口(数据接口也就是service 接口)
		String[] needRoles = dataAuthChecker.needRoles();
		// 获取数据鉴权接口的实现类
		Class<?> authCheckerClass = dataAuthChecker.authChecker();
		// 只有角色校验和自定义方法校验都通过了, 才通过
		if (checkRoles(needRoles, userAuthority) && checkCustom(authCheckerClass, userAuthority)) {
			return;
		}
		// 否则抛出访问被拒绝的业务异常
		throw new BusinessException(ResultCode.ACCESS_DENY);

	}

	/**
	* @Description: 校验角色 
	* @author 影法師 
	* @date 2020年8月28日 下午12:42:03 
	* @version V1.0 
	* @param @param needRoles
	* @param @param userAuthority
	* @param @return    
	* @return boolean    
	* @throws
	 */
	private boolean checkRoles(String[] needRoles, UserAuthority userAuthority) {
		// 用户拥有的角色
		List<String> userRoles = userAuthority.getRoles();
		try {
			// 检查用户拥有的角色是否可以通过角色
			userRoles.stream().filter(role -> {
				for (int i = 0; i < needRoles.length; i++) {
					if (role.equals(needRoles[i])) {
						return true;
					}
				}
				return false;
			}).findFirst().get();
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/**
	* @Description: 自定义方法校验数据权限 
	* @author 影法師 
	* @date 2020年8月28日 下午12:42:10 
	* @version V1.0 
	* @param @param authChecker
	* @param @param userAuthority
	* @param @return    
	* @return boolean
	* @throws
	 */
	private boolean checkCustom(Class<?> authCheckerClass, UserAuthority userAuthority) throws Exception {
		// 如果开发人员编码不规范, 开发的数据接口鉴权实现类不是 AuthChecker 的实现类的话, 则抛异常
		if (authCheckerClass.isAssignableFrom(AuthChecker.class)) {
			throw new BusinessException(ResultCode.AUTHCHECKER_NOT_REGULAR);
		}
		// 实例化一个数据接口鉴权器
		AuthChecker authChecker = (AuthChecker) authCheckerClass.newInstance();
		// 执行数据接口鉴权
		return (Boolean) authCheckerClass
				.getMethod(AuthChecker.class.getDeclaredMethods()[0].getName(), UserAuthority.class)
				.invoke(authChecker, userAuthority);
	}

}
